#include <Ape/Collections/LinkedList.h>
#include <Ape/MT/Mutex.h>
#include <Ape/Exception.h>

namespace Ape {
	namespace Collections {
		using Ape::MT::MutexLock;
		
		LL_Joint* LL_Joint::Create() {
			LL_Joint* j = new LL_Joint;
			j->Value = NULL;
			j->Prev = NULL;
			j->Next = NULL;
			return j;
		}
		
		LinkedList_Impl::LinkedList_Impl()
				: m_First (NULL),
				m_Last (NULL),
				m_Count (0)
		{
			InitObjectMutex();
		}
		LinkedList_Impl::~LinkedList_Impl() {
		}
		
		void LinkedList_Impl::DisposeValues() {
			MutexLock lock (GetObjectMutex() );
			for (LL_Joint* j = m_First; j != NULL;) {
				LL_Joint* tmp = j;
				j = j->Next;
				DisposeValue (tmp->Value);
				delete tmp;
			}
			m_First = NULL;
			m_Last = NULL;
		}
		
		void LinkedList_Impl::InitFirstValue (void* value) {
			m_First = LL_Joint::Create();
			m_Last = m_First;
			m_First->Value = value;
		}
		
		void LinkedList_Impl::_Append (void* value) {
			MutexLock lock (GetObjectMutex() );
			if (!m_Last) {
				InitFirstValue (value);
				m_Count = 1;
				return;
			}
			m_Last->Next = LL_Joint::Create();
			m_Last->Next->Prev = m_Last;
			m_Last = m_Last->Next;
			m_Last->Value = value;
			m_Count++;
		}
		
		void LinkedList_Impl::_Prepend (void* value) {
			MutexLock lock (GetObjectMutex() );
			if (!m_First) {
				InitFirstValue (value);
				m_Count = 1;
				return;
			}
			m_First->Prev = LL_Joint::Create();
			m_First->Prev->Next = m_First;
			m_First = m_First->Prev;
			m_First->Value = value;
			m_Count++;
		}
		
		void* LinkedList_Impl::_FetchFirst() {
			MutexLock lock (GetObjectMutex() );
			if (!m_First) {
				throw Exception (L"Attempt to fetch element from empty list");
			}
			LL_Joint* j = m_First;
			m_First = m_First->Next;
			if (m_First) {
				m_First->Prev = NULL;
			}
			void* retVal = j->Value;
			delete j;
			m_Count--;
			return retVal;
			
		}
		void* LinkedList_Impl::_FetchLast() {
			MutexLock lock (GetObjectMutex() );
			if (!m_Last) {
				throw Exception (L"Attempt to fetch element from empty list");
			}
			LL_Joint* j = m_Last;
			m_Last = m_Last->Prev;
			if (m_Last) {
				m_Last->Next = NULL;
			}
			void* retVal = j->Value;
			delete j;
			m_Count--;
			return retVal;
		}
		
		size_t LinkedList_Impl::get_Count() const {
			MutexLock lock (GetObjectMutex() );
			return m_Count;
		}
		
		LL_Joint* LinkedList_Impl::_GetFirstJoint() const {
			return m_First;
		}
	}
}
